#pragma once
#include "util.hpp"
#include <mutex>
#include <thread>
#include <cassert>

class user_table
{
private:
    MYSQL *_mysql;     // mysql操作句柄
    std::mutex _mutex; // 互斥保护访问数据库
public:
    user_table(const std::string &host, const std::string &username, const std::string &password,
               const std::string &dbname, uint16_t port)
    {
        _mysql = mysql_util::mysql_create(host, username, password, dbname, port);
        assert(_mysql);
    }
    ~user_table()
    {
        if (_mysql)
        {
            mysql_util::mysql_destroy(_mysql);
            _mysql = nullptr;
        }
    }
    // 注册新增用户
    bool insert(Json::Value &user)
    {
        // 如果用户名重复，那么直接返回错误
        // {
        //     std::unique_lock<std::mutex> lock(_mutex);
        //     #define SELECT_FOR_USER "select * from user where username='%s';"
        //     char sql[4096] = {0};
        //     std::string name = user["username"].asString();
        //     sprintf(sql, SELECT_FOR_USER, name.c_str());
        //     bool ret = mysql_util::mysql_exec(_mysql, sql);
        //     if (ret == false)
        //     {
        //         DLOG("get user by name failed!");
        //         return false;
        //     }
        //     // 获取到信息
        //     MYSQL_RES* res = mysql_store_result(_mysql);
        //     if (res != nullptr)
        //     {
        //         free(res);
        //         DLOG("already has user info!");
        //         return false;
        //     }
        // }
#define INSERT_USER "insert into user values(null,'%s',password('%s'),1000,0,0);"
        if (user["username"].isNull() || user["password"].isNull())
        {
            DLOG("please input username and password!");
            return false;
        }
        char sql[4096] = {0};
        sprintf(sql, INSERT_USER, user["username"].asCString(), user["password"].asCString());
        bool ret = mysql_util::mysql_exec(_mysql, sql);
        if (ret == false)
        {
            DLOG("insert user failed!");
            return false;
        }
        return true;
    }
    bool login(Json::Value &user) // 登陆时返回详细的用户信息
    {
#define LOGIN_USER "select id,score,total_count,win_count from user where username='%s' and password=password('%s');"
        if (user["username"].isNull() || user["password"].isNull())
        {
            DLOG("please input username and password!");
            return false;
        }
        char sql[4096] = {0};
        sprintf(sql, LOGIN_USER, user["username"].asCString(), user["password"].asCString());
        MYSQL_RES *res = nullptr;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            bool ret = mysql_util::mysql_exec(_mysql, sql);
            if (ret == false)
            {
                DLOG("user login failed!");
                return false;
            }
            // 没有获取到信息
            res = mysql_store_result(_mysql);
            if (res == nullptr)
            {
                DLOG("has no user info!");
                return false;
            }
        }
        // 这里可能获得的信息不唯一
        int row = mysql_num_rows(res);
        if (row > 1)
        {
            DLOG("user info is no unique!");
            return false;
        }
        MYSQL_ROW rows = mysql_fetch_row(res);
        user["id"] = (Json::UInt64)std::stol(rows[0]);
        user["score"] = (Json::UInt64)std::stol(rows[1]);
        user["total_count"] = std::stoi(rows[2]);
        user["win_count"] = std::stoi(rows[3]);
        // 记得释放结果集
        mysql_free_result(res);
        return true;
    }
    bool select_by_name(const std::string &name, Json::Value &user) // 通过名字来查询信息
    {
#define USER_BY_NAME "select id,score,total_count,win_count from user where username='%s';"
        char sql[4096] = {0};
        sprintf(sql, USER_BY_NAME, name.c_str());
        MYSQL_RES *res = nullptr;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            bool ret = mysql_util::mysql_exec(_mysql, sql);
            if (ret == false)
            {
                DLOG("get user by name failed!");
                return false;
            }
            // 没有获取到信息
            res = mysql_store_result(_mysql);
            if (res == nullptr)
            {
                DLOG("has no user info!");
                return false;
            }
        }
        // 这里可能获得的信息不唯一
        int row = mysql_num_rows(res);
        if (row > 1)
        {
            DLOG("user info is no unique!");
            return false;
        }
        MYSQL_ROW rows = mysql_fetch_row(res);
        user["username"] = name;
        user["id"] = (Json::UInt64)std::stol(rows[0]);
        user["score"] = (Json::UInt64)std::stol(rows[1]);
        user["total_count"] = std::stoi(rows[2]);
        user["win_count"] = std::stoi(rows[3]);
        // 记得释放结果集
        mysql_free_result(res);
        return true;
    }
    bool select_by_id(uint64_t id, Json::Value &user) // 通过id来查询信息
    {
#define USER_BY_ID "select username,score,total_count,win_count from user where id=%d;"
        char sql[4096] = {0};
        sprintf(sql, USER_BY_ID, id);
        MYSQL_RES *res = nullptr;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            bool ret = mysql_util::mysql_exec(_mysql, sql);
            if (ret == false)
            {
                DLOG("get user by id failed!");
                return false;
            }
            // 没有获取到信息
            res = mysql_store_result(_mysql);
            if (res == nullptr)
            {
                DLOG("has no user info!");
                return false;
            }
        }
        // 这里可能获得的信息不唯一
        int row = mysql_num_rows(res);
        if (row > 1)
        {
            DLOG("user info is no unique!");
            return false;
        }
        MYSQL_ROW rows = mysql_fetch_row(res);
        user["username"] = rows[0];
        user["id"] = (Json::UInt64)id;
        user["score"] = (Json::UInt64)std::stol(rows[1]);
        user["total_count"] = std::stoi(rows[2]);
        user["win_count"] = std::stoi(rows[3]);
        // 记得释放结果集
        mysql_free_result(res);
        return true;
    }
    // 赢了对数据进行更新,天梯分数+30,胜利场次+1,总场次+1
    bool win(uint64_t id)
    {
#define USER_WIN "update user set score=score+30,win_count=win_count+1,total_count=total_count+1 where id=%d;"
        char sql[4096] = {0};
        sprintf(sql, USER_WIN, id);
        bool ret = mysql_util::mysql_exec(_mysql, sql);
        if (ret == false)
        {
            DLOG("update win user failed!");
            return false;
        }
        return true;
    }
    // 输了对数据进行更新,天梯分数+30,胜利场次不变,总场次+1
    bool lose(uint64_t id)
    {
#define USER_LOSE "update user set score=score-30,total_count=total_count+1 where id=%d;"
        char sql[4096] = {0};
        sprintf(sql, USER_LOSE, id);
        bool ret = mysql_util::mysql_exec(_mysql, sql);
        if (ret == false)
        {
            DLOG("update lose user failed!");
            return false;
        }
        return true;
    }
};